// UNIX时间戳
function unixTime() {
	const uT = Math.floor(Date.now() / 1000);
	return uT;
}
// 随机数
function randT() {
	return Math.floor(Math.random() * 0x8000);
}

// 密钥转换
const ppr_code = ['a', 'A', '0', 'B', 'b', 'c', 'C', 'D', 'd', '1', 'e', 'E', 'F', 'f', 'g', 'G', '2', 'H', 'h', 'i', 'I', 'J', 'j', '3', 'k', 'K', 'L', 'l', 'm', 'M', '4', 'N', 'n', 'o', 'O', 'P', 'p', '5', 'q', 'Q', 'R', 'r', 's', 'S', '6', 'T', 't', 'u', 'U', 'V', 'v', '7', 'w', 'W', 'X', 'x', 'y', 'Y', '8', 'Z', 'z', '9', '+', '=', '!', '-', '@', '$', '%', '&'];
function time_str(t1, t2) {
	var tt1 = BigInt(t1);
	var tt2 = BigInt(t2);
	var num = tt1 * (tt2 * tt2) * 20090312n % 18446744073709551616n;
	
	var ans = "";
	while (num != 0n) {
		ans = ans + (ppr_code[Number(num % 70n)]);
		num = num / 70n;
	}
	return ans;
}

// 编码转换
const ranges = [
	[0xA1, 0xA9, 0xA1, 0xFE],
	[0xB0, 0xF7, 0xA1, 0xFE],
	[0x81, 0xA0, 0x40, 0xFE],
	[0xAA, 0xFE, 0x40, 0xA0],
	[0xA8, 0xA9, 0x40, 0xA0],
	[0xAA, 0xAF, 0xA1, 0xFE],
	[0xF8, 0xFE, 0xA1, 0xFE],
	[0xA1, 0xA7, 0x40, 0xA0],
];
const codes = new Uint16Array(23940);
let i = 0;

for (const [b1Begin, b1End, b2Begin, b2End] of ranges) {
	for (let b2 = b2Begin ; b2 <= b2End ; b2++) {
		if (b2 !== 0x7F) {
			for (let b1 = b1Begin; b1 <= b1End; b1++) {
				codes[i++] = b2 << 8 | b1;
			}
		}
	}
}
const str = new TextDecoder('gbk').decode(codes);

const table = new Uint16Array(65536);
var tableno = new Uint16Array(65536);
for (let i = 0 ; i < str.length ; i++) {
	table[str.charCodeAt(i)] = codes[i];
	tableno[codes[i]] = str.charCodeAt(i);
}
function StringToGbk(str) {
	const buf = new Uint8Array(str.length * 2);
	let n = 0;

	for (let i = 0 ; i < str.length ; i++) {
		const code = str.charCodeAt(i);
		if (code < 0x80) {
			buf[n++] = code;
		}
		else {
			const gbk = table[code];
			buf[n++] = gbk & 0xFF;
			buf[n++] = gbk >> 8;
		}
	}
	return buf.subarray(0, n);
}
function GbkToString(buf) {
	const str = new Uint16Array(buf.length);
	let n = 0;

	for (let i = 0 ; i < buf.length ; i++) {
		const code = buf[i];
		if (code < 0x80) {
			str[n++] = code;
		}
		else {
			const gbk = code + (buf[i + 1] << 8);
			console.log(gbk);
			str[n++] = tableno[gbk];
			i++;
		}
	}
	return str.subarray(0, n);
}

// Base64
const base64en = [
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
	'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
	'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
	's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2',
	'3', '4', '5', '6', '7', '8', '9', '+', '/'
];
const base64_suffix_map = [
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
	255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 62,  255, 255, 255, 63,
	52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  255, 255,
	255, 254, 255, 255, 255, 0,   1,   2,   3,   4,   5,   6,
	7,   8,   9,   10,  11,  12,  13,  14,  15,  16,  17,  18,
	19,  20,  21,  22,  23,  24,  25,  255, 255, 255, 255, 255,
	255, 26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
	37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
	49,  50,  51,  255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255
];

// 剪贴板操作
function copyToClipboard(text) {
	const textArea = document.createElement('textarea');
	textArea.style.position = 'fixed';
	textArea.style.visibility = '-10000px';
	textArea.value = text;
	document.body.appendChild(textArea);
	textArea.focus();
	textArea.select();
	if (!document.execCommand('copy')) {
		document.body.removeChild(textArea);
		return false;
	}
	else {
		document.body.removeChild(textArea);
		return true;
	}
}

// 响应
function ppr_encode() {
	var k1 = unixTime();
	var k2 = randT();
	var key = time_str(k1, k2);
	var tstr = document.getElementById('TextArea1').value;
	var str = StringToGbk(tstr);

	var i = 0;
	var j = 0;

	var length = 0;
	var ans = 0;
	var anstr = "";

	while (i < str.length) {
		if (j == key.length) {
			j = 0;
		}

		if (str[i] == 10) {
			var code = 13 ^ key[j].charCodeAt();

			ans = (ans << 8) | code;
			length = length + 8;
			
			while (length >= 6) {
				let t = ans >> (length - 6);
				length = length - 6;
				ans = ans & ((1 << length) - 1);
				anstr = anstr + base64en[t];
			}

			j = j + 1;
			if (j == key.length) {
				j = 0;
			}

			var code = 10 ^ key[j].charCodeAt();

			ans = (ans << 8) | code;
			length = length + 8;

			while (length >= 6) {
				let t = ans >> (length - 6);
				length = length - 6;
				ans = ans & ((1 << length) - 1);
				anstr = anstr + base64en[t];
			}

			i = i + 1;
			j = j + 1;
		}
		else {
			var code = str[i] ^ key[j].charCodeAt();
			
			ans = (ans << 8) | code;
			length = length + 8;
			
			while (length >= 6) {
				let t = ans >> (length - 6);
				length = length - 6;
				ans = ans & ((1 << length) - 1);
				anstr = anstr + base64en[t];
			}

			i = i + 1;
			j = j + 1;
		}
	}

	var emp = 0;
	if ((length > 0) && (length < 6)) {
		emp = 6 - length;
		ans = ans << emp;
		length = 6;
	}
	while (length >= 6) {
		let t = ans >> (length - 6);
		length = length - 6;
		ans = ans & ((1 << length) - 1);
		anstr = anstr + base64en[t];
	}
	while (emp) {
		emp = emp - 2;
		anstr = anstr + '=';
	}

	document.getElementById('TextArea3').value = String(k1) + " " + String(k2) + " " + anstr;
	copyToClipboard(document.getElementById('TextArea3').value);
}
function ppr_decode() {
	var alls = document.getElementById('TextArea3').value;
	var arr = alls.split(" ");
	var k1 = arr[0];
	var k2 = arr[1];
	var str = arr[2];
	var key = time_str(k1, k2);

	// str + ken -> ans
	var length = 0;
	var now = 0;
	var ans = [];
	var j = 0;
	for (let i = 0 ; i < str.length ; i++) {
		if (str[i] == '=') {
			now <<= 2;
			length -= 2;
		}
		else {
			let c = base64_suffix_map[str[i].charCodeAt()];
			now = (now << 6) | c;
			length += 6;
		}

		while (length >= 8) {
			let t = now >> (length - 8);
			ans.push(t ^ key[j].charCodeAt());
			j++;
			if (j == key.length) {
				j = 0;
			}
			length -= 8;
			now = now & ((1 << length) - 1);
		}
	}
	if (length > 0) {
		let t = now << (8 - length);
		ans.push(t ^ key[j].charCodeAt());
	}

	const STR = GbkToString(ans);
	var ansSTR = "";
	for (let i = 0 ; i < STR.length ; i++) {
		ansSTR = ansSTR + String.fromCharCode(STR[i]);
	}

	document.getElementById('TextArea1').value = ansSTR;
	copyToClipboard(document.getElementById('TextArea1').value);
}